namespace WP7Contrib.Services.BingMaps.Model
{
    using System;
    using System.Device.Location;
    using Common;

    public class WayPoint : BaseModel, ICriterion<WayPoint>, IEquatable<WayPoint>, ICloneable<WayPoint>
    {
        private GeoCoordinate point;
        private Landmark landmark;
        private Address address;

        public WayPoint()
        {
            this.point = new GeoCoordinate();
            this.landmark = new Landmark();
            this.address = new Address();
        }

        public GeoCoordinate Point
        {
            get
            {
                return this.point;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.point, value, () => this.Point);
            }
        }

        public bool HasPoint
        {
            get { return this.point != null && this.point != GeoCoordinate.Unknown; }
        }

        public Landmark Landmark
        {
            get
            {
                return this.landmark;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.landmark, value, () => this.Landmark);
            }
        }

        public bool HasLandmark
        {
            get { return this.landmark != null && this.landmark != Landmark.Empty; }
        }

        public Address Address
        {
            get
            {
                return this.address;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.address, value, () => this.Address);
            }
        }

        public bool HasAddress
        {
            get { return this.address != null && this.address != Address.Empty; }
        }

        public WayPoint Reset()
        {
            this.point = new GeoCoordinate();
            this.landmark = new Landmark();
            this.address = new Address();

            return this;
        }

        public static bool operator ==(WayPoint wp1, WayPoint wp2)
        {
            return Equals(wp1, wp2);
        }

        public static bool operator !=(WayPoint wp1, WayPoint wp2)
        {
            return !Equals(wp1, wp2);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }

            return obj is WayPoint && this.Equals((WayPoint)obj);
        }

        public override int GetHashCode()
        {
            return this.CombineHashCodes(this.Address, this.Landmark, this.Point);
        }

        public bool Equals(WayPoint waypoint)
        {
            if (ReferenceEquals(null, waypoint))
            {
                return false;
            }

            if (this.Address != waypoint.Address)
            {
                return false;
            }

            if (this.Landmark != waypoint.Landmark)
            {
                return false;
            }

            if (this.Point != waypoint.Point)
            {
                return false;
            }

            return true;
        }

        public WayPoint ShallowClone()
        {
            var waypoint = new WayPoint
            {
                Address = this.Address,
                Landmark = this.Landmark,
                Point = this.Point
            };

            return waypoint;
        }

        public WayPoint DeepClone()
        {
            var waypoint = new WayPoint
            {
                Address = this.Address.DeepClone(),
                Landmark = this.Landmark != null ? this.Landmark.DeepClone() : null,
                Point = this.Point != null ? new GeoCoordinate(Point.Latitude, Point.Longitude) : null
            };

            return waypoint;
        }
    }
}